﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SuperKit
{
    class CollectionBuilder : CommandExecutor {
        class BuilderCollection {
            public CollectionBuilder Parent { get; }
            private List<BuilderItem> Items { get; }
            public string OutputName { get; private set; }
            public int Index { get; internal set; }
            public bool IsTest => Parent.Arg.IsTest;

            public BuilderCollection(CollectionBuilder parent) {
                this.Parent = parent;
                Items = new List<BuilderItem>();
            }

            public int Count {
                get {
                    int count = 0;
                    foreach (var i in Items) {
                        count += i.Count;
                    }
                    return count;
                }
            }


            public void Add(BuilderItem i) {
                Items.Add(i);
            }

            public void CalculateName() {
                if (Parent.UseDirName) {
                    var parentName = Path.GetFileNameWithoutExtension(Parent.FilePath);
                    OutputName = string.Format("{0} Vol {1}", parentName,  Index + 1);
                } else if (Kit.IsEmpty(Parent.UseNameFormat)) {
                    OutputName = CalculateFullName(0);
                    if (Parent.MaxNameLength != 0 && OutputName.Length > Parent.MaxNameLength) {
                        OutputName = CalculateShortenName();
                    }
                } else {
                    OutputName = string.Format(Parent.UseNameFormat, Index + 1);
                }                
            }

            private string CalculateShortenName() {
                int limit = Parent.MaxNameLength / Items.Count;
                return CalculateFullName(limit);
            }

            private string CalculateFullName(int limit) {
                StringBuilder sb = new StringBuilder();
                foreach (var i in Items) {
                    if (sb.Length > 0) {
                        sb.Append("+");
                    }
                    sb.Append(Kit.AutoShorten(i.Name, limit));
                }
                return sb.ToString();
            }

            public void Collect() {
                if (Items.Count <= 1) {
                    return;
                }

                var path = Path.Combine(Parent.FilePath, OutputName);
                if (Directory.Exists(path) == false) {
                    if (!IsTest) {
                        Directory.CreateDirectory(path);
                    }                    
                }

                foreach (var i in Items) {
                    var movePath = Path.Combine(path, i.Dir.Name);
                    //Parent.Flush("Move:{0}", i.Dir.FullName);
                    //Parent.Flush("MoveTo:{0}", movePath);
                    if (Kit.IsEqual(i.Dir.FullName, movePath)) {
                        // 这种情况是合集中只剩下他一个人，所以名称只有他自己，不做变化
                        continue;
                    }
                    if (!IsTest) {
                        try {
                            Directory.Move(i.Dir.FullName, movePath);
                        } catch (Exception e) {
                            Parent.Flush(e.Message);
                        }
                        
                    }
                    
                    //i.Dir.FullName
                }
            }


        }

        class BuilderItem {
            public CollectionBuilder Parent { get; }
            public DirectoryInfo Dir { get; }
            public int Count { get; }
            public string Name { get => Dir.Name; }

            public BuilderItem(CollectionBuilder parent, DirectoryInfo dir, int count) {
                this.Parent = parent;
                this.Dir = dir;
                this.Count = count;
            }

        }

        /// <summary>合集的上限</summary>
        public int PageCount { get; }
        /// <summary>超过这个值，则不需要计入合集</summary>
        public int LimitCount { get; }
        /// <summary>是否需要减化名称，配置简化名称的上限。如果配置为0，表示不简化名称。
        /// 如果最近合集的名称大于这个名称，则每个项目使用最简单的名称。</summary>
        public int MaxNameLength { get; }
        /// <summary>直接指定名称的格式</summary>
        public string UseNameFormat { get; }
        public bool UseDirName { get; }
        private List<BuilderItem> Items { get; }
        private List<BuilderCollection> Pages { get; }
        private BuilderCollection Current { get; set; }

        public CollectionBuilder(ArgReader arg, IExecutorOwner form, string fpath) : base(arg, form, fpath) {
            LimitCount = arg.GetInteger("-limitCount", 300);
            PageCount = arg.GetInteger("-pageCount", 300);
            MaxNameLength = arg.GetInteger("-maxNameLength", 0);
            UseNameFormat = arg.GetParameter("-useNameFormat");
            UseDirName = arg.IsContain("-useDirName");
            Items = new List<BuilderItem>();
            Pages = new List<BuilderCollection>();
        }

        public override void Execute() {
            base.Execute();
            GainedCollections();

            if (Items.Count == 0) {
                Flush("没有需要整理合集的目录！");
                End();
                return;
            }

            Gather();
            Redispatch();
            End();
        }

        private void Redispatch() {
            foreach (var i in Pages) {
                i.CalculateName();
                i.Collect();
                Flush("Output:{0}", i.OutputName);
            }
        }

        private void Gather() {
            foreach (var i in Items) {
                StackTo(i);
            }
        }

        private void StackTo(BuilderItem i) {
            if (Current == null) {
                CreateNewPage();
            }
            if (Current.Count > PageCount) {
                CreateNewPage();
            }
            Current.Add(i);
        }

        private void CreateNewPage() {
            Current = new BuilderCollection(this);
            Current.Index = Pages.Count;
            Pages.Add(Current);
        }

        private void GainedCollections() {
            DirectoryInfo dir = new DirectoryInfo(FilePath);
            var dirs = dir.GetDirectories();
            foreach (var i in dirs) {
                int count = DirectoryEx.GetFileCount(i, Kit.IMG_EXTS);
                if (count >= LimitCount) {
                    continue;
                }
                Items.Add(new BuilderItem(this, i, count));
            }
        }
    }
}
